package plgbase

import (
	"dgo/MyProj/PrjConf"
	"dgo/goutils/utils"
	"fmt"
	"gitee.com/ymofen/gobase"
	"gitee.com/ymofen/gobase/subpub"
	"gitee.com/ymofen/supervalue"
	"strings"
	"sync"
	"time"
)

var (
	appname string
	approot string

	conf_file  string
	BUILD_TIME string = "2020-12-23_11:32:01"
	EXP_TIME   time.Time
	PlgWarning *utils.SyncCycleList
	closewg    sync.WaitGroup

	plgNotifyCenter = subpub.NewSubchannel()
)

var PlgFnBuildTime = func() string {
	return BUILD_TIME
}

func GetStartupConfigFile() string {
	conffile := conf_file
	if ok, v := utils.InvokeFactoryVarFunc("startup.config-file", nil); ok {
		conffile = utils.GetStrValue(v, "")
	}
	return conffile
}

func AppCloseWgAdd() {
	closewg.Add(1)
}

func AppCloseWgWait() {
	closewg.Wait()
}

func AppCloseWgDone() {
	closewg.Done()
}

func AddNotifyFunc(id string, channel string, fn subpub.SubFunc) {
	plgNotifyCenter.Sub(id, channel, fn)
}

func DelNotifyFunc(id string, channel string) {
	plgNotifyCenter.Unsub(id, channel)
}

func PubNotify(channel string, args ...interface{}) {
	plgNotifyCenter.Pub(channel, 0, args...)
}

/*
同一个ID只能订阅一次, ID相同会被覆盖
*/
func AddSysReloadNotify(id interface{}, fn func()) {
	plgNotifyCenter.Sub(gobase.ObjectHexAddr(id), "/plug/reload", func(id, topic string, args ...interface{}) (ok bool) {
		go func() {
			if gobase.GoFunCatchException {
				defer gobase.DeferCatchPanic()
			}
			fn()
		}()
		return true
	})
}

func DelSysReloadNotify(id interface{}) {
	plgNotifyCenter.Unsub(gobase.ObjectHexAddr(id), "/plug/reload")
}

// 通知重载
func SysReloadNotify(args ...interface{}) {
	plgNotifyCenter.Pub("/plug/reload", 0, args...)
}

func ReplacePlaceholderEx(s string) string {

	for {
		id := utils.GetBetween(s, "$$", "$$", 0)
		if len(id) == 0 {
			break
		}

		if ok, v := utils.InvokeFactoryVarFunc(id, nil); ok {
			replkey := fmt.Sprintf("$$%s$$", id)
			s = strings.ReplaceAll(s, replkey, utils.GetStrValue(v, ""))
		}
	}
	return s
}

func ReplacePlaceholder(s string) string {
	s = strings.ReplaceAll(s, "$appuuid$", PrjConf.APP_UUID)
	return s
}

func ReplacePlaceholderVars(s string) string {
	s = utils.ReplacePlaceholder(s, "$$", "$$")

	var cmdaddr string = ""
	var conffile string = conf_file
	if ok, v := utils.InvokeFactoryVarFunc("startup.cmd-addr", nil); ok {
		cmdaddr = utils.GetStrValue(v, "")
	}

	if ok, v := utils.InvokeFactoryVarFunc("startup.config-file", nil); ok {
		conffile = utils.GetStrValue(v, "")
	}
	s = strings.ReplaceAll(s, "$appuuid$", PrjConf.APP_UUID)
	s = strings.ReplaceAll(s, "$approot$", approot)
	s = strings.ReplaceAll(s, "$appname$", appname)
	s = strings.ReplaceAll(s, "$configfile$", conffile)
	s = strings.ReplaceAll(s, "$cmd-addr$", cmdaddr)
	s = strings.ReplaceAll(s, "$buildtime$", BUILD_TIME)
	return s
}

func ReplacePlaceholderForFileName(s string) string {
	var cmdaddr string = ""
	var conffile string = conf_file
	if ok, v := utils.InvokeFactoryVarFunc("startup.cmd-addr", nil); ok {
		cmdaddr = utils.GetStrValue(v, "")
	}

	if ok, v := utils.InvokeFactoryVarFunc("startup.config-file", nil); ok {
		conffile = utils.GetStrValue(v, "")
	}
	s = ReplacePlaceholder(s)
	s = strings.ReplaceAll(s, "$approot$", approot)
	s = strings.ReplaceAll(s, "$appname$", appname)
	s = strings.ReplaceAll(s, "$configfile$", conffile)
	s = strings.ReplaceAll(s, "$cmd-addr$", cmdaddr)
	s = strings.ReplaceAll(s, "$buildtime$", BUILD_TIME)
	s = utils.ParseTimeFmt(s, time.Now())
	return s
}

func GetSubscribeFromVal(val interface{}) *utils.SubscribeCenter {
	if v, ok := val.(IGetSubscriber); ok {
		return v.GetSubscriber()
	}
	if sc, ok := val.(*utils.SubscribeCenter); ok {
		return sc
	}
	return nil
}

/*
**

	插件ReleaseFlag的值

-1: 未知

	1: 已经释放
*/
func PlugIsReleased(val interface{}) int {
	if val == nil {
		return 1
	}
	if plgU, ok := val.(IPlugUtils); ok {
		return plgU.GetReleaseFlag()
	}

	return -1
}

func FindPluginByID(id string) interface{} {
	obj := utils.FindObjPojoByGroup(pluggroup, id)
	if obj != nil {
		return obj.GetObject()
	} else {
		return nil
	}
}

// 关闭当前插件
func closePlugObject(pojo *utils.ObjPojo) {
	obj := pojo.GetObject()
	if obj == nil {
		return
	}
	PlgNotifyEx.Pub(PLUG_EVENT_BEFORE_CLOSE, 0, pojo.GetId(), pojo.GetObject())

	// 通知之前对象不再使用了
	if ok, _, _ := utils.TryObjectNotify(obj, pojo, utils.NOTIFY_TYPE_RELEASE, nil); ok { // 已经通知Release

	} else { //
		utils.TryClose(obj) // 执行关闭
	}
	PlgNotifyEx.Pub(PLUG_DISP_RELEASE, 0, obj, pojo.GetId(), nil)
}

func DeferPlugs() {
	pluggroup.Range(func(key, value interface{}) bool {
		pojo := value.(*utils.ObjPojo)
		obj := pojo.GetObject()
		if obj != nil {
			closePlugObject(pojo)
		}
		pluggroup.Remove(key)
		return true
	})
}

func TryDispatchData(plg interface{}, channelid string, sender interface{}, data interface{}, tag interface{}) (err error) {
	if sc, ok := plg.(IDispatchData); ok {
		return sc.DispatchData(channelid, sender, data, tag)
	} else if sc, ok := plg.(ISendKVs); ok {
		return sc.SendKVs(channelid, data)
	} else {
		return fmt.Errorf("%v不支持分发接口", plg)
	}
}

func NewSVArgs(useCache bool, args ...interface{}) (*wrapper.SuperValue, error) {
	if len(args) == 0 {
		return nil, nil
	}

	if json, ok := args[0].(*wrapper.SuperValue); ok {
		return json.CloneCache(useCache), nil
	} else if strMap, ok := args[0].(gobase.StrMap); ok {
		json := wrapper.NewSVObjectCache(useCache)
		json.CopyFromStrMap(strMap)
		return json, nil
	} else if strMap, ok := args[0].(*gobase.StrMap); ok {
		json := wrapper.NewSVObjectCache(useCache)
		json.CopyFromStrMap(*strMap)
		return json, nil
	} else if str, ok := args[0].(string); ok {
		if len(str) > 2 {
			if (str[0] == '{' && str[len(str)-1] == '}') || (str[0] == '[' && str[len(str)-1] == ']') {
				return wrapper.NewSVFromBufCache([]byte(str), useCache)
			}

			if strings.Index(str, "=") != -1 {
				json := wrapper.NewSVObjectCache(useCache)
				json.CopyFromURLString(str)
				return json, nil
			}
		}
	} else if buf, ok := args[0].([]byte); ok {
		if len(buf) > 2 {
			if (buf[0] == '{' && buf[len(buf)-1] == '}') || (buf[0] == '[' && buf[len(buf)-1] == ']') {
				return wrapper.NewSVFromBufCache(buf, useCache)
			}
		}
	}

	return nil, nil
}
